from app_analysevar import _insc
import wx
import wx.html
from collections import OrderedDict
import numpy as np
from wxPopupError import popuperror
from htmltool import htmlparag, htmllist, htmltabrow, htmlparInformTab
from g_tool import get_paramlist
import sys
import traceback

class AnalyseIncaParam:
    def analyse_incaParam(self, text, dev='CCP: 1'):
        """归纳、分析INCA变量的信息，并输出HTML"""

        templist = get_paramlist(text)
        paramlist = []
        for x in templist:
            if (not x in paramlist): paramlist.append(x)
        if not paramlist:
            return
        print('link with inca ...')
        ins = _insc.IncaControl()
        ins.init()
        assert dev in ins.device.keys(), 'INCA当前实验环境不支持数据源:"%s"' % dev
        ins.a2l_init(dev)
        data = {}

        data['nowdevice'] = dev
        data['device'] = tuple(ins.device.keys())
        assert dev in data['device'], '不存在的源数据集:"%s"' % dev
        data['a2l'] = ins.a2l.GetDescriptionFileName()

        cset = set(ins.a2l.GetAllElementNamesOfType('allCharacteristics'))
        mset = set(ins.a2l.GetAllElementNamesOfType('allMeasurements'))
        aset = set(ins.a2l.GetAllElementNamesOfType('allAxisPoints'))

        data['found'] = found = []  # 找到的变量
        data['foundcs'] = foundcs = []  # 找到的单参标定量
        data['foundco'] = foundco = []  # 找到的一维表
        data['foundct'] = foundct = []  # 找到的二维表
        data['foundcay'] = foundcay = []  # 找到的数组
        data['foundm'] = foundm = []  # 找到的测量量
        data['founda'] = founda = []  # 找到的轴
        data['nofound'] = nofound = []  # 没找到
        data['nosure'] = nosure = []  # 不确定类型的变量
        data['caliable'] = caliable = []  # 可标的
        data['calidisable'] = calidisable = []  # 不可标的
        data['inform'] = {}  # name : datatuple
        # (单位,下限,上限,精度,地址,数据类型,备注)
        data['value'] = {}  # 包含各标定量的值，类型有浮点数、列表、嵌套元组

        print('find params ...')
        for name in paramlist:
            try:
                print('find', name)
                if name in cset:
                    elem = ins.exp.GetExperimentElementInDevice(name, ins.device[dev])
                    elema2l = ins.a2l.GetCharacteristicNamed(name)
                    elemval = elem.GetValue()
                    if elem.IsScalar():  # 单参标定量
                        temp = ins.geta2ldata(elema2l)
                        try:
                            value = elemval.GetDoublePhysValue()
                            if value == None:
                                raise Exception()
                        except:
                            value = elemval.GetLongImplValue()

                        if elemval.IsWriteProtected():
                            calidisable.append(name)
                        else:
                            caliable.append(name)

                        data['inform'][name] = temp
                        data['value'][name] = value
                        found.append(name)
                        foundcs.append(name)
                    elif elem.IsOneDTable():  # 一维表
                        temp = ins.geta2ldata(elema2l)
                        try:
                            value = (elemval.GetValue().GetDoublePhysValue(),
                                        elemval.GetDistribution().GetDoublePhysValue())
                            if None in value:
                                raise Exception()
                        except:
                            t_data = elemval.GetValue()
                            t_axis = elemval.GetDistribution()
                            value = (t_data.GetLongImplValuesRange(1, t_data.GetSize()),
                                        t_axis.GetLongImplValuesRange(1, t_axis.GetSize()))

                        if elemval.GetValue().IsWriteProtected():
                            calidisable.append(name)
                        else:
                            caliable.append(name)

                        data['inform'][name] = temp
                        data['value'][name] = value
                        found.append(name)
                        foundco.append(name)
                    elif elem.IsTwoDTable():  # 二维表
                        temp = ins.geta2ldata(elema2l)
                        try:
                            value = (elemval.GetValue().GetDoublePhysValue(),
                                        elemval.GetXDistribution().GetDoublePhysValue(),
                                        elemval.GetYDistribution().GetDoublePhysValue())
                            if None in value:
                                raise Exception()
                        except:
                            t_matrix = elemval.GetValue()
                            t_xaxis = elemval.GetXDistribution()
                            t_yaxis = elemval.GetYDistribution()
                            tmp = np.array(t_matrix.GetLongImplValuesRange(1, 1, t_matrix.GetXSize(), t_matrix.GetYSize()))
                            value = (tuple(tuple(x) for x in tmp.T.tolist()),
                                     t_xaxis.GetLongImplValuesRange(1, t_xaxis.GetSize()),
                                     t_yaxis.GetLongImplValuesRange(1, t_yaxis.GetSize()))

                        if elemval.GetValue().IsWriteProtected():
                            calidisable.append(name)
                        else:
                            caliable.append(name)

                        data['inform'][name] = temp
                        data['value'][name] = value
                        found.append(name)
                        foundct.append(name)
                    elif elem.IsArray():  # 数组
                        temp = ins.geta2ldata(elema2l)
                        try:
                            value = elemval.GetDoublePhysValue()
                            if None == value:
                                raise Exception()
                        except:
                            value = elemval.GetLongImplValuesRange(1, elemval.GetSize())
                        value = (value, tuple(range(len(value))))

                        if elemval.IsWriteProtected():
                            calidisable.append(name)
                        else:
                            caliable.append(name)

                        data['inform'][name] = temp
                        data['value'][name] = value
                        found.append(name)
                        foundcay.append(name)
                    else:
                        nosure.append(name)

                elif name in mset:  # 测量量
                    elema2l = ins.a2l.GetMeasurementNamed(name)
                    temp = ins.geta2ldata(elema2l)

                    data['inform'][name] = temp
                    found.append(name)
                    foundm.append(name)
                elif name in aset:  # 轴
                    elema2l = ins.a2l.GetAxisPointNamed(name)
                    elemval = ins.exp.GetExperimentElementInDevice(name, ins.device[dev]).GetValue()

                    temp = ins.geta2ldata(elema2l)
                    try:
                        value = elemval.GetDoublePhysValue()
                        if None == value:
                            raise Exception()
                    except:
                        value = elemval.GetLongImplValuesRange(1, elemval.GetSize())

                    if elemval.IsWriteProtected():
                        calidisable.append(name)
                    else:
                        caliable.append(name)

                    data['inform'][name] = temp
                    data['value'][name] = value
                    found.append(name)
                    founda.append(name)
                else:
                    nofound.append(name)
            except Exception as e:
                nosure.append(name)

        print('almost ...')
        myhtml = self.get_htmlFromIncaInform(data)
        return myhtml

    def get_htmlFromIncaInform(self, data):
        parag = OrderedDict()
        parag['overview'] = HTML_IncaInform_Overview.format(data=data, allnum=len(data['found']),
                                                            errnum=len(data['nofound']) + len(data['nosure']))

        parag['error'] = HTML_IncaInform_Error.format(htmllist(data['nofound']),
                                                      htmllist(data['nosure']))

        informstr = htmlparInformTab(data['inform'], data['found'])
        parag['inform'] = HTML_IncaInform_Inform.format(informstr)

        if data['found']:
            valuelist = []
            for name in data['found']:
                if name in data['foundcs']:  # 单参标定量
                    val = data['value'][name]
                    valuelist.append('<li><b>{0}</b></li>\n{1!s}'.format(name, val))
                elif name in data['foundco'] or name in data['foundcay']:  # 一维表 or 数组
                    val = data['value'][name]
                    valuelist.append("""<li><b>{0}</b></li>
                    <table border="1" cellpadding="2" cellspacing="0">
                    {1}
                    {2}
                    </table>
                    """.format(name, htmltabrow(val[1]), htmltabrow(val[0])))
                elif name in data['foundct']:  # 二维表
                    val = data['value'][name]
                    tabstr = htmltabrow(('y|x',) + val[1])
                    temptuple = (val[2],) + val[0]  # 添加Y轴
                    tempmatrix = np.array(temptuple)
                    for row in tempmatrix.T:  # 转置
                        tabstr += htmltabrow(row)
                    valuelist.append("""<li><b>{0}</b></li>
                    <table border="1" cellpadding="2" cellspacing="0">
                    {1}
                    </table>\n""".format(name, tabstr))
                elif name in data['founda']:  # 轴
                    val = data['value'][name]
                    valuelist.append("""<li><b>{0}</b></li>
                    <table border="1" cellpadding="2" cellspacing="0">
                    {1}
                    </table>
                    """.format(name, htmltabrow(val)))
            valuestr = '<ul>\n' + ''.join(valuelist) + '\n</ul>'
        else:
            valuestr = '<ul>\n</ul>'
        parag['value'] = htmlparag('标定量数值', refname='value').format(valuestr)

        parag['foundm'] = htmlparag('测量量', refname='foundm').format(htmllist(sorted(data['foundm']), True))
        parag['foundcs'] = htmlparag('单参标定量', refname='foundcs').format(htmllist(sorted(data['foundcs']), True))
        parag['foundco'] = htmlparag('一维表', refname='foundco').format(htmllist(sorted(data['foundco']), True))
        parag['foundct'] = htmlparag('二维表', refname='foundct').format(htmllist(sorted(data['foundct']), True))
        parag['founda'] = htmlparag('轴', refname='founda').format(htmllist(sorted(data['founda']), True))
        parag['caliable'] = htmlparag('可标定标定量', refname='caliable').format(htmllist(sorted(data['caliable']), True))
        parag['calidisable'] = htmlparag('不可标定标定量', refname='calidisable').format(
            htmllist(sorted(data['calidisable']), True))

        return HTML_IncaInform_Main.format(body=''.join(parag.values())
                                           , h2style='{background-color:#B0E0E6;\npadding:8px;}\n')



class InformIncaParamWin(wx.Frame):
    """根据用户输入显示INCA变量信息的窗口"""

    def __init__(self, parent, mainobj):
        wx.Frame.__init__(self, parent=parent, title='INCA变量信息',
                          size=(650, 700), style=wx.DEFAULT_FRAME_STYLE | wx.FRAME_FLOAT_ON_PARENT)
        self.mainobj = mainobj

        self.pl = wx.Panel(self, size=(650, 700))

        self.textwin = wx.StaticText(self.pl, label='把测量量\标定量名称复制到下面窗口(以换行分隔)',
                                     style=wx.ALIGN_CENTRE_HORIZONTAL)
        self.parwin = wx.TextCtrl(self.pl, style=wx.TE_MULTILINE | wx.TE_DONTWRAP)
        self.devchoice = wx.Choice(self.pl, style=wx.CB_SORT)
        self.bt = wx.Button(self.pl, label='开始', size=(80, 40))
        self.text_log = wx.TextCtrl(self.pl, style=wx.TE_MULTILINE | wx.TE_READONLY, size=(80, 80))

        self.sizer = wx.GridBagSizer(5, 10)
        self.sizer.Add(self.textwin, pos=(0, 0), span=(1, 1), flag=wx.EXPAND | wx.TOP | wx.LEFT, border=10)
        self.sizer.Add(self.parwin, pos=(1, 0), span=(3, 1), flag=wx.EXPAND | wx.LEFT, border=10)
        self.sizer.Add(20, 20, pos=(1, 1), span=(1, 1), flag=wx.EXPAND)
        self.sizer.Add(self.devchoice, pos=(2, 1), span=(1, 1), flag=wx.EXPAND | wx.RIGHT, border=10)
        self.sizer.Add(self.bt, pos=(3, 1), span=(1, 1), flag=wx.ALL, border=20)
        self.sizer.Add(self.text_log, pos=(4, 0), span=(1, 2), flag=wx.ALL | wx.EXPAND, border=10)
        self.sizer.Add(20, 20, pos=(5, 0), span=(1, 2), flag=wx.EXPAND)

        self.sizer.AddGrowableCol(0)
        self.sizer.AddGrowableRow(1)
        self.pl.SetSizer(self.sizer)

        self.Bind(wx.EVT_BUTTON, self.on_button, self.bt)

        self.Centre()
        self.Show()
        self.pl.Layout()
        self.refresh_devchoice()

    @popuperror
    def refresh_devchoice(self, default='CCP: 1'):
        self.devchoice.Clear()
        ins = _insc.IncaControl()
        ins.init()
        for dev in ins.device:
            self.devchoice.AppendItems(dev)
        if default in ins.device:
            self.devchoice.SetSelection(self.devchoice.FindString(default, True))
        else:
            self.devchoice.SetSelection(0)

    def on_button(self, event):
        self.bt.Disable()
        self.mainobj.set_stdout(self.text_log)
        text = self.parwin.GetValue()
        dev = self.devchoice.GetStringSelection()
        if text and dev:
            print('waiting ...')
            try:
                myhtml = AnalyseIncaParam().analyse_incaParam(text, dev)
                wx.CallAfter(self.mainobj.gui.showhtml, myhtml)
                print('done')
            except AssertionError as e:
                wx.LogError(str(e))
            except:
                wx.LogError(traceback.format_exc())
            finally:
                self.bt.Enable()
        self.mainobj.unset_stdout(self.text_log)
        self.bt.Enable()



########################################## HTML ####################################################
HTML_IncaInform_Inform = """
<p>
<h2><a name="inform">变量信息</a></h2>
<dl>
<dt></dt>
    <dd>
    {0}
    </dd>
</dl>
</p>
"""

HTML_IncaInform_Error = """
<p>
<h2><a name="error">错误变量</a></h2>
<ul>
<li><b>未找到的变量</b></li>
{0}
<li><b>信息出错的变量</b></li>
{1}
</ul>
</p>
"""

HTML_IncaInform_Overview = """
<p>
<h2>总览</h2>
<ul>
<li><b>A2L描述</b>: {data[a2l]}</li>
<li><b>数据源</b>: {data[nowdevice]}</li>
<li><b>所有的数据源</b>: {data[device]}</li>
<li><b>找到变量</b>: {allnum} 个</li>
<li color="#DC143C"><b>出错的变量</b>: <strong>{errnum}</strong> 个</li>
<li><b>索引</b></li>
    <ul>
    <li><a href="#error">错误变量</a></li>
    <li><a href="#inform">变量信息</a></li>
    <li><a href="#value">标定量数值</a></li>
    <li><a href="#foundm">找到的测量量</a></li>
    <li><a href="#foundcs">找到的单参标定量</a></li>
    <li><a href="#foundco">找到的一维表</a></li>
    <li><a href="#foundct">找到的二维表</a></li>
    <li><a href="#founda">找到的轴</a></li>
    <li><a href="#caliable">可标定标定量</a></li>
    <li><a href="#calidisable">不可标定标定量</a></li>
    </ul>
</ul>
</p>
"""


HTML_IncaInform_Main = """<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="author" content="XiePeng">
<title>变量信息</title>
<style type="text/css">
h2 {h2style}
</style>
</head>
<body>
{body}
</body>
</html>
"""
